package com.hzhr.iot.core.util.generator;

import com.hzhr.iot.core.annotation.ApiImplicitInternalParams;
import com.hzhr.iot.core.util.HzhrFileUtil;
import com.hzhr.iot.core.util.HzhrReflectUtil;
import com.hzhr.iot.core.util.HzhrStringUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class ServiceAspectGenerator {
    public static String projectName;
    public static String rootPath;
    public static String rootPackageName;

    public static void run() throws Exception {
        String srcRootPath = rootPath;

        Set<Class<?>> classes = HzhrReflectUtil.getClasses(rootPackageName + ".service");
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        for (Class<?> clazz : classes) {
            String clazzName = clazz.getName();
            String clazzSimpleName = clazz.getSimpleName();

            if (clazzSimpleName.endsWith("Service") && !"BaseService".equals(clazzSimpleName)) {
                Integer queryIndex = null;
                Integer headerIndex = null;

                StringBuilder importSb = new StringBuilder();
                StringBuilder contentSb = new StringBuilder();
                importSb.append("package " + rootPackageName + ".aop.service;\n");
                importSb.append("\n");
                importSb.append("import " + rootPackageName + ".service.base.BaseService;\n");
                importSb.append("import " + rootPackageName + ".service.util.CheckUtil;\n");
                importSb.append("import org.aspectj.lang.ProceedingJoinPoint;\n");
                importSb.append("import org.aspectj.lang.annotation.Aspect;\n");
                importSb.append("import org.aspectj.lang.annotation.Around;\n");
                importSb.append("import org.springframework.core.annotation.Order;\n");
                importSb.append("import org.springframework.stereotype.Component;\n");
                importSb.append("import org.springframework.util.StringUtils;\n");
                importSb.append("import java.util.HashMap;\n");
                importSb.append("import java.util.Map;\n");
                importSb.append("import com.hzhr.iot.core.constant.Common_ErrorsEnum;\n");
                importSb.append("import com.hzhr.iot.core.exception.ServiceException;\n");
                contentSb.append("\n");
                contentSb.append("@Aspect\n");
                contentSb.append("@Component\n");
                contentSb.append("@Order(2)\n");
                contentSb.append("public class " + clazzSimpleName + "Aspect extends BaseService {\n");

                Method[] methods = clazz.getDeclaredMethods();
                for (Method method:
                methods) {
                    String[] parameterNames = u.getParameterNames(method);

                    boolean hasHeader = false;
                    for (String parameterName:
                    parameterNames) {
                        if ("header".equals(parameterName)) {
                            hasHeader = true;
                        }
                    }
                    if (!hasHeader) {
                        continue;
                    }

                    String methodName = method.getName();
                    contentSb.append("    @Around(\"execution(* " + rootPackageName + ".service." + clazzSimpleName + "." + methodName + "(..))\")\n");
                    contentSb.append("    public Object " + methodName + "(ProceedingJoinPoint joinPoint) throws Throwable {\n");
                    contentSb.append("        Object[] args = joinPoint.getArgs();\n");


                    for (int i = 0; i < parameterNames.length; i++) {
                        String parameter = parameterNames[i];
                        if ("header".equals(parameter)) {
                            headerIndex = i;
                            contentSb.append("        Map<String, String> header = (Map<String, String>) args[" + i + "];\n");
                            contentSb.append("        if (header == null) {\n");
                            contentSb.append("            header = new HashMap<>();\n");
                            contentSb.append("        }\n");
                        } else if ("query".equals(parameter)) {
                            queryIndex = i;
                            contentSb.append("        Map<String, Object> query = (Map<String, Object>) args[" + i + "];\n");
                            contentSb.append("        if (query == null) {\n");
                            contentSb.append("            query = new HashMap<>();\n");
                            contentSb.append("        }\n");
                        } else if (!"body".equals(parameter)) {
                            contentSb.append("        Object " + parameter + " = args[" + i + "];\n");
                        }
                    }
                    contentSb.append("\n");

                    List<String> pathValues = new ArrayList<>();
                    int j = 0;
                    int k = 0;
                    for (String parameterName:
                    parameterNames) {
                        if ("header".equals(parameterName)) {
                            //contentSb.append("        CheckUtil.checkHeader(header);\n");
                        } else if ("body".equals(parameterName)) {
                            Class<?> bodyType = method.getParameterTypes()[k];

                            if (j == 0) {
                                importSb.append("import " + bodyType.getName() + ";\n");
                                contentSb.append("        " + bodyType.getSimpleName() + " body = (" + bodyType.getSimpleName() + ")args[" + k + "];\n");
                            }
                            contentSb.append("        if (body == null) {\n");
                            contentSb.append("            throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"body不能为空\");\n");
                            contentSb.append("        }\n");

                            Field[] fields = bodyType.getDeclaredFields();
                            for (Field field :
                            fields) {
                                String fieldName = field.getName();
                                ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
                                if (apiModelProperty != null) {
                                    boolean required = apiModelProperty.required();
                                    if (required) {
                                        contentSb.append("        if (StringUtils.isEmpty(body.get" + HzhrStringUtils.firstCharToUppserCase(fieldName) + "())) {\n");
                                        contentSb.append("            throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"body." + fieldName + "不能为空\");\n");
                                        contentSb.append("        }\n");
                                    }
                                }
                            }
                            j++;
                        } else {
                            if (!"query".equals(parameterName)) {
                                contentSb.append("        if (StringUtils.isEmpty(" + parameterName + ")) {\n");
                                contentSb.append("            throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"path." + parameterName + "不能为空\");\n");
                                contentSb.append("        }\n");
                            }

                        }
                        k++;
                    }

                    contentSb.append("\n");

                    String resourceName = clazzSimpleName.substring(0, clazzSimpleName.lastIndexOf("Service"));
                    Class<?> serviceClass = null;
                    try {
                        serviceClass = Class.forName(rootPackageName + ".service." + resourceName + "Service");
                    } catch (Exception e) {

                    }
                    if (serviceClass != null) {
                        Map<String, String> queryMap = new HashMap<>();
                        Map<String, String> headerMap = new HashMap<>();

                        int ik = 0;
                        Method[] controllerMethods = serviceClass.getMethods();
                        for (Method controllerMethod:
                        controllerMethods ) {
                            if (controllerMethod.getName().equals(methodName)) {
                                ApiImplicitParams apiImplicitParams = controllerMethod.getAnnotation(ApiImplicitParams.class);
                                if (apiImplicitParams != null) {
                                    ApiImplicitParam[] apiImplicitParamArr = apiImplicitParams.value();
                                    for (ApiImplicitParam apiImplicitParam :
                                    apiImplicitParamArr) {
                                        if ("query".equals(apiImplicitParam.paramType())) {
                                            queryMap.put(apiImplicitParam.name(), apiImplicitParam.defaultValue());
                                        }
                                        if ("header".equals(apiImplicitParam.paramType())) {
                                            headerMap.put(apiImplicitParam.name(), apiImplicitParam.defaultValue());
                                        }
                                    }
                                }

                                ApiImplicitInternalParams apiImplicitInternalParams = controllerMethod.getAnnotation(ApiImplicitInternalParams.class);
                                if (apiImplicitInternalParams != null) {
                                    ApiImplicitParam[] apiImplicitParamArr = apiImplicitInternalParams.value();
                                    for (ApiImplicitParam apiImplicitParam :
                                            apiImplicitParamArr) {
                                        if ("query".equals(apiImplicitParam.paramType())) {
                                            queryMap.put(apiImplicitParam.name(), apiImplicitParam.defaultValue());
                                        }
                                        if ("header".equals(apiImplicitParam.paramType())) {
                                            headerMap.put(apiImplicitParam.name(), apiImplicitParam.defaultValue());
                                        }
                                    }
                                }
                            }
                        }



                        contentSb.append("        Map<String, String> headerTmp = new HashMap<>();\n");
                        for (Map.Entry<String, String> entry:
                                headerMap.entrySet()) {
                            String key = entry.getKey();
                            String defaultValue = entry.getValue();
                            if (key.startsWith("_")) {
                                contentSb.append("        if (!StringUtils.isEmpty(header.get(\"" + key + "\"))) {\n");
                                contentSb.append("            headerTmp.put(\"" + key + "\", header.get(\"" + key + "\"));\n");
                                contentSb.append("        }\n");
                            }
                        }
                        for (Map.Entry<String, String> entry:
                                headerMap.entrySet()) {
                            String key = entry.getKey();
                            String defaultValue = entry.getValue();
                            if (!key.startsWith("_")) {
                                contentSb.append("        if (!StringUtils.isEmpty(header.get(\"" + key + "\"))) {\n");
                                contentSb.append("            headerTmp.put(\"_" + key + "\", header.get(\"" + key + "\"));\n");
                                contentSb.append("        }\n");
                            }
                        }

                        contentSb.append("\n");

                        contentSb.append("        Map<String, Object> queryTmp = new HashMap<>();\n");
                        contentSb.append("        if (isInternalServiceInvok(headerTmp)) {\n");
                        for (Map.Entry<String, String> entry:
                             queryMap.entrySet()) {
                            String key = entry.getKey();
                            String defaultValue = entry.getValue();
                            if (key.startsWith("_")) {
                                String key1 = key.substring(1);
                                contentSb.append("            if (!StringUtils.isEmpty(query.get(\"" + key + "\"))) {\n");
                                contentSb.append("                queryTmp.put(\"" + key + "\", query.get(\"" + key + "\"));\n");
                                contentSb.append("            } else if (!StringUtils.isEmpty(query.get(\"" + key1 + "\"))) {\n");
                                contentSb.append("                queryTmp.put(\"" + key + "\", query.get(\"" + key1 + "\"));\n");
                                contentSb.append("            }\n");
                            }
                        }
                        contentSb.append("        } else {\n");
                        for (Map.Entry<String, String> entry:
                                queryMap.entrySet()) {
                            String key = entry.getKey();
                            String defaultValue = entry.getValue();
                            if (!key.startsWith("_")) {
                                contentSb.append("            if (!StringUtils.isEmpty(query.get(\"" + key + "\"))) {\n");
                                contentSb.append("                queryTmp.put(\"_" + key + "\", query.get(\"" + key + "\"));\n");
                                contentSb.append("            }\n");
                            }
                        }

                        contentSb.append("        }\n");

                        contentSb.append("\n");

                        contentSb.append("        if (isInternalServiceInvok(headerTmp)) {\n");
                        for (Method controllerMethod:
                                controllerMethods ) {
                            if (controllerMethod.getName().equals(methodName)) {
                                ApiImplicitInternalParams apiImplicitInternalParams = controllerMethod.getAnnotation(ApiImplicitInternalParams.class);
                                if (apiImplicitInternalParams != null) {
                                    ApiImplicitParam[] apiImplicitParamArr = apiImplicitInternalParams.value();
                                    for (ApiImplicitParam apiImplicitParam :
                                            apiImplicitParamArr) {
                                        if ("query".equals(apiImplicitParam.paramType())) {
                                            if (apiImplicitParam.name().startsWith("_")) {
                                                if (apiImplicitParam.required()) {
                                                    contentSb.append("            if (StringUtils.isEmpty(queryTmp.get(\"" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                Map<String, Object> objectInfo = new HashMap<>();\n");
                                                    contentSb.append("                objectInfo.put(\"query\", queryTmp);\n");
                                                    contentSb.append("                throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"query." + apiImplicitParam.name() + "不能为空\", objectInfo);\n");
                                                    contentSb.append("            }\n");
                                                } else if (!StringUtils.isEmpty(apiImplicitParam.defaultValue())) {
                                                    contentSb.append("            if (StringUtils.isEmpty(queryTmp.get(\"" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                queryTmp.put(\"" + apiImplicitParam.name() + "\", \"" + apiImplicitParam.defaultValue() + "\");\n");
                                                    contentSb.append("            }\n");
                                                }
                                            }
                                        }
                                        if ("header".equals(apiImplicitParam.paramType())) {
                                            if (apiImplicitParam.name().startsWith("_")) {
                                                if (apiImplicitParam.required()) {
                                                    contentSb.append("            if (StringUtils.isEmpty(headerTmp.get(\"" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                Map<String, Object> objectInfo = new HashMap<>();\n");
                                                    contentSb.append("                objectInfo.put(\"header\", headerTmp);\n");
                                                    contentSb.append("                throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"header." + apiImplicitParam.name() + "不能为空\", objectInfo);\n");
                                                    contentSb.append("            }\n");
                                                } else if (!StringUtils.isEmpty(apiImplicitParam.defaultValue())) {
                                                    contentSb.append("            if (StringUtils.isEmpty(headerTmp.get(\"" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                headerTmp.put(\"" + apiImplicitParam.name() + "\", \"" + apiImplicitParam.defaultValue() + "\");\n");
                                                    contentSb.append("            }\n");
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        contentSb.append("        } else {\n");
                        for (Method controllerMethod:
                                controllerMethods ) {
                            if (controllerMethod.getName().equals(methodName)) {
                                ApiImplicitParams apiImplicitInternalParams = controllerMethod.getAnnotation(ApiImplicitParams.class);
                                if (apiImplicitInternalParams != null) {
                                    ApiImplicitParam[] apiImplicitParamArr = apiImplicitInternalParams.value();
                                    for (ApiImplicitParam apiImplicitParam :
                                            apiImplicitParamArr) {
                                        if ("query".equals(apiImplicitParam.paramType())) {
                                            if (!apiImplicitParam.name().startsWith("_")) {
                                                if (apiImplicitParam.required()) {
                                                    contentSb.append("            if (StringUtils.isEmpty(queryTmp.get(\"_" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                Map<String, Object> objectInfo = new HashMap<>();\n");
                                                    contentSb.append("                objectInfo.put(\"query\", queryTmp);\n");
                                                    contentSb.append("                throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"query." + apiImplicitParam.name() + "不能为空\", objectInfo);\n");
                                                    contentSb.append("            }\n");
                                                } else if (!StringUtils.isEmpty(apiImplicitParam.defaultValue())) {
                                                    contentSb.append("            if (StringUtils.isEmpty(queryTmp.get(\"_" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                queryTmp.put(\"_" + apiImplicitParam.name() + "\", \"" + apiImplicitParam.defaultValue() + "\");\n");
                                                    contentSb.append("            }\n");
                                                }
                                            }
                                        }
                                        if ("header".equals(apiImplicitParam.paramType())) {
                                            if (!apiImplicitParam.name().startsWith("_")) {
                                                if (apiImplicitParam.required()) {
                                                    contentSb.append("            if (StringUtils.isEmpty(headerTmp.get(\"_" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                Map<String, Object> objectInfo = new HashMap<>();\n");
                                                    contentSb.append("                objectInfo.put(\"header\", headerTmp);\n");
                                                    contentSb.append("                throw new ServiceException(Common_ErrorsEnum.COMMON_6, \"header." + apiImplicitParam.name() + "不能为空\", objectInfo);\n");
                                                    contentSb.append("            }\n");
                                                } else if (!StringUtils.isEmpty(apiImplicitParam.defaultValue())) {
                                                    contentSb.append("            if (StringUtils.isEmpty(headerTmp.get(\"_" + apiImplicitParam.name() + "\"))) {\n");
                                                    contentSb.append("                headerTmp.put(\"" + apiImplicitParam.name() + "\", \"" + apiImplicitParam.defaultValue() + "\");\n");
                                                    contentSb.append("            }\n");
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        contentSb.append("        }\n");
                    }

                    if (queryIndex != null) {
                        contentSb.append("\n");
                        contentSb.append("        if (!StringUtils.isEmpty(queryTmp.get(\"_is_paging\")) && !Boolean.parseBoolean(queryTmp.get(\"_is_paging\").toString())) {\n");
                        contentSb.append("            queryTmp.put(\"_page\", null);\n");
                        contentSb.append("            queryTmp.put(\"_count\", null);\n");
                        contentSb.append("        }\n");
                        contentSb.append("        args[" + queryIndex + "] = queryTmp;\n");
                    }
                    if (headerIndex != null) {
                        contentSb.append("        args[" + headerIndex + "] = headerTmp;\n");
                    }
                    contentSb.append("        return joinPoint.proceed(args);\n");

                    contentSb.append("    }\n");
                }

                contentSb.append("}\n");
                HzhrFileUtil.writeContent(srcRootPath + "\\aop\\service\\" + clazzSimpleName + "Aspect.java", importSb.toString() + contentSb.toString());
            }
        }
    }
}
